LVGL (6) 基础对象 Obj 分析 |
您所在的位置:网站首页 › asserted state › LVGL (6) 基础对象 Obj 分析 |
LVGL 中使用 lv_obj_t 来对常用的对象进行抽象: typedef struct _lv_obj_t { const lv_obj_class_t * class_p; struct _lv_obj_t * parent; _lv_obj_spec_attr_t * spec_attr; _lv_obj_style_t * styles; #if LV_USE_USER_DATA void * user_data; #endif lv_area_t coords; lv_obj_flag_t flags; lv_state_t state; uint16_t layout_inv : 1; uint16_t scr_layout_inv : 1; uint16_t skip_trans : 1; uint16_t style_cnt : 6; uint16_t h_layout : 1; uint16_t w_layout : 1; } lv_obj_t;obj 结构作为 LVGL 内的一个基本抽象,包含了 area,style,parent 等内容; 以一个 button 为例,应用层代码创建一个 button 的代码; 创建对象 void LVGL_CentralButton(void) { lv_obj_t *btn = lv_btn_create(lv_scr_act()); lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); lv_obj_set_height(btn, 30); lv_obj_t *label; label = lv_label_create(btn); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_label_set_text(label, "LVGL"); static lv_style_t style_btn; lv_style_init(&style_btn); lv_style_set_radius(&style_btn, 10); lv_style_set_border_color(&style_btn, lv_color_white()); lv_style_set_border_opa(&style_btn, LV_OPA_30); lv_obj_add_style(btn, &style_btn, LV_STATE_DEFAULT); }首先定义了一个 lv_obj_t *btn 的一个对象,然后调用 lv_btn_create 来创建一个 button; #define MY_CLASS &lv_btn_class const lv_obj_class_t lv_btn_class = { .constructor_cb = lv_btn_constructor, .width_def = LV_SIZE_CONTENT, .height_def = LV_SIZE_CONTENT, .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, .instance_size = sizeof(lv_btn_t), .base_class = &lv_obj_class }; lv_obj_t * lv_btn_create(lv_obj_t * parent) { LV_LOG_INFO("begin"); lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); lv_obj_class_init_obj(obj); return obj; }在每个组件中(比如 button、label)都定义了一个 MY_CLASS 的玩意,而且仅该文件使用,充分体现了 LVGL 将组件抽象为 class 的思想; 这个MY_CLASS 是一个 lv_obj_class_t 结构; 每一个 lv_obj_class_t 结构都包含了他的构造函数和析构函数,默认长宽等信息,如下所示: typedef struct _lv_obj_class_t { const struct _lv_obj_class_t * base_class; void (*constructor_cb)(const struct _lv_obj_class_t * class_p, struct _lv_obj_t * obj); void (*destructor_cb)(const struct _lv_obj_class_t * class_p, struct _lv_obj_t * obj); #if LV_USE_USER_DATA void * user_data; #endif void (*event_cb)(const struct _lv_obj_class_t * class_p, struct _lv_event_t * e); /**< Widget type specific event function*/ lv_coord_t width_def; lv_coord_t height_def; uint32_t editable : 2; /**< Value from ::lv_obj_class_editable_t*/ uint32_t group_def : 2; /**< Value from ::lv_obj_class_group_def_t*/ uint32_t instance_size : 16; } lv_obj_class_t;创建一个 button 的时候,首先调用 lv_obj_class_create_obj 函数,然后再调用 lv_obj_class_init_obj; lv_btn_create |--> lv_obj_class_create_obj |--> lv_obj_class_init_obj一个是创建 obj,另一个是初始化 obj; 来看一下 lv_obj_class_create_obj: lv_obj_t * lv_obj_class_create_obj(const lv_obj_class_t * class_p, lv_obj_t * parent) { LV_TRACE_OBJ_CREATE("Creating object with %p class on %p parent", (void *)class_p, (void *)parent); uint32_t s = get_instance_size(class_p); lv_obj_t * obj = lv_mem_alloc(s); if(obj == NULL) return NULL; lv_memset_00(obj, s); obj->class_p = class_p; obj->parent = parent; /*Create a screen*/ if(parent == NULL) { LV_TRACE_OBJ_CREATE("creating a screen"); lv_disp_t * disp = lv_disp_get_default(); if(!disp) { LV_LOG_WARN("No display created yet. No place to assign the new screen"); return NULL; } if(disp->screens == NULL) { disp->screens = lv_mem_alloc(sizeof(lv_obj_t *)); disp->screens[0] = obj; disp->screen_cnt = 1; } else { disp->screen_cnt++; disp->screens = lv_mem_realloc(disp->screens, sizeof(lv_obj_t *) * disp->screen_cnt); disp->screens[disp->screen_cnt - 1] = obj; } /*Set coordinates to full screen size*/ obj->coords.x1 = 0; obj->coords.y1 = 0; obj->coords.x2 = lv_disp_get_hor_res(NULL) - 1; obj->coords.y2 = lv_disp_get_ver_res(NULL) - 1; } /*Create a normal object*/ else { LV_TRACE_OBJ_CREATE("creating normal object"); LV_ASSERT_OBJ(parent, MY_CLASS); if(parent->spec_attr == NULL) { lv_obj_allocate_spec_attr(parent); } if(parent->spec_attr->children == NULL) { parent->spec_attr->children = lv_mem_alloc(sizeof(lv_obj_t *)); parent->spec_attr->children[0] = obj; parent->spec_attr->child_cnt = 1; } else { parent->spec_attr->child_cnt++; parent->spec_attr->children = lv_mem_realloc(parent->spec_attr->children, sizeof(lv_obj_t *) * parent->spec_attr->child_cnt); parent->spec_attr->children[parent->spec_attr->child_cnt - 1] = obj; } } return obj; }主要就是创建了 obj 对象; 下面调用 lv_obj_class_init_obj 对 obj 进行初始化: void lv_obj_class_init_obj(lv_obj_t * obj) { // 标记 screen 为 dirty (设置 scr->scr_layout_inv = 1),在更新 layout 的时候会用到; lv_obj_mark_layout_as_dirty(obj); // 禁止 style 刷新 lv_obj_enable_style_refresh(false); lv_theme_apply(obj); // 调用对应组件的构造函数; lv_obj_construct(obj); // 使能 style 刷新 lv_obj_enable_style_refresh(true); lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY); lv_obj_refresh_self_size(obj); lv_group_t * def_group = lv_group_get_default(); if(def_group && lv_obj_is_group_def(obj)) { lv_group_add_obj(def_group, obj); } lv_obj_t * parent = lv_obj_get_parent(obj); if(parent) { /*Call the ancestor's event handler to the parent to notify it about the new child. *Also triggers layout update*/ lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj); lv_event_send(parent, LV_EVENT_CHILD_CREATED, obj); /*Invalidate the area if not screen created*/ // 标记为 obj 无效,即需要被更新 lv_obj_invalidate(obj); } }屏幕,是没有父类的基础对象; 小结所以,可以看到,通过如下方式进行创建 button 的时候 (打个比方) lv_obj_t *btn = lv_btn_create(lv_scr_act()); lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); lv_obj_set_height(btn, 30);那么这个 button 的 parent 就会被指定为当前的 scr_act 屏幕; |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |